package support;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelOperator {
	/**
	 * @param head
	 *            the first row, i.e., the head of the sheet
	 * **/
	public void write(String path, String sheetName, double[][] data,
			List<String> head) {
		if (data == null || data.length == 0 || data[0].length == 0)
			return;

		int m = data.length;
		int n = data[0].length;

		Workbook wb = null;
		try {
			File file = new File(path);
			if (!file.exists()) {
				createWorkBook(path, sheetName);
				file = new File(path);
			}
			wb = new XSSFWorkbook(new FileInputStream(file));
			Sheet sheet = wb.getSheet(sheetName);
			if (sheet == null)
				sheet = wb.createSheet(sheetName);
			if (sheet != null) {
				int rowIndex = 0;
				if (head != null && head.size() > 0) {
					Row row = sheet.getRow(rowIndex);
					if (row == null)
						row = sheet.createRow(rowIndex);
					for (int k = 0; k < head.size(); k++) {
						Cell cell = row.getCell(k);
						if (cell == null)
							cell = row.createCell(k);
						cell.setCellValue(head.get(k));
					}
					rowIndex++;
				}
				for (int i = 0; i < m; i++) {
					Row row = sheet.getRow(i + rowIndex);
					if (row == null)
						row = sheet.createRow(i + rowIndex);
					for (int k = 0; k < n; k++) {
						Cell cell = row.getCell(k);
						if (cell == null)
							cell = row.createCell(k);
						cell.setCellValue(data[i][k]);
					}
				}
			}
			OutputStream os = new FileOutputStream(file);
			wb.write(os);
			os.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void writeInfo(String path, String sheetName, List<String> infos) {
		if (infos == null || infos.size() == 0)
			return;

		Workbook wb = null;
		try {
			File file = new File(path);
			if (!file.exists()) {
				createWorkBook(path, sheetName);
				file = new File(path);
			}
			wb = new XSSFWorkbook(new FileInputStream(file));
			Sheet sheet = wb.getSheet(sheetName);
			if (sheet == null)
				sheet = wb.createSheet(sheetName);
			if (sheet != null) {
				for (int i = 0; i < infos.size(); i++) {
					Row row = sheet.getRow(i);
					if (row == null)
						row = sheet.createRow(i);
					Cell cell = row.getCell(0);
					if (cell == null)
						cell = row.createCell(0);
					cell.setCellValue(infos.get(i));
				}
			}
			OutputStream os = new FileOutputStream(file);
			wb.write(os);
			os.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * @param head
	 *            the first row, i.e., the head of the sheet
	 * @param startRow
	 *            The index of row starting to write
	 * **/
	public void write(String path, String sheetName, double[][] data,
			List<String> head, int startRow, int startCol) {
		if (data == null || data.length == 0 || data[0].length == 0)
			return;

		int m = data.length;
		int n = data[0].length;

		Workbook wb = null;
		try {
			File file = new File(path);
			if (!file.exists()) {
				createWorkBook(path, sheetName);
				file = new File(path);
			}
			wb = new XSSFWorkbook(new FileInputStream(file));
			Sheet sheet = wb.getSheet(sheetName);
			if (sheet == null)
				sheet = wb.createSheet(sheetName);
			if (sheet != null) {
				int rowIndex = startRow;
				if (head != null && head.size() > 0) {
					Row row = sheet.getRow(rowIndex);
					if (row == null)
						row = sheet.createRow(rowIndex);
					for (int k = 0; k < head.size(); k++) {
						Cell cell = row.getCell(startCol + k);
						if (cell == null)
							cell = row.createCell(k + startCol);
						cell.setCellValue(head.get(k));
					}
					rowIndex++;
				}
				for (int i = 0; i < m; i++) {
					Row row = sheet.getRow(i + rowIndex);
					if (row == null)
						row = sheet.createRow(i + rowIndex);
					for (int k = 0; k < n; k++) {
						Cell cell = row.getCell(k + startCol);
						if (cell == null)
							cell = row.createCell(k + startCol);
						cell.setCellValue(data[i][k]);
					}
				}
			}
			OutputStream os = new FileOutputStream(file);
			wb.write(os);
			os.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void write(String path, String sheetName, double[] data) {
		if (data == null || data.length == 0)
			return;

		int m = data.length;

		Workbook wb = null;
		try {
			File file = new File(path);
			if (!file.exists()) {
				createWorkBook(path, sheetName);
				file = new File(path);
			}
			wb = new XSSFWorkbook(new FileInputStream(file));
			Sheet sheet = wb.getSheet(sheetName);
			if (sheet == null)
				sheet = wb.createSheet(sheetName);
			if (sheet != null) {
				for (int i = 0; i < m; i++) {
					Row row = sheet.getRow(i);
					if (row == null)
						row = sheet.createRow(i);
					Cell cell = row.getCell(0);
					if (cell == null)
						cell = row.createCell(0);
					cell.setCellValue(data[i]);
				}
			}
			OutputStream os = new FileOutputStream(file);
			wb.write(os);
			os.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public void write(String path, String sheetName, List<Double[]> data) {
		if (data == null || data.size() == 0)
			return;

		int m = data.size();
		int n = data.get(0).length;

		Workbook wb = null;
		try {
			File file = new File(path);
			if (!file.exists()) {
				createWorkBook(path, sheetName);
				file = new File(path);
			}
			wb = new XSSFWorkbook(new FileInputStream(file));
			Sheet sheet = wb.getSheet(sheetName);
			if (sheet == null)
				sheet = wb.createSheet(sheetName);
			if (sheet != null) {
				for (int i = 0; i < m; i++) {
					Row row = sheet.getRow(i);
					if (row == null)
						row = sheet.createRow(i);
					for (int k = 0; k < n; k++) {
						Cell cell = row.getCell(k);
						if (cell == null)
							cell = row.createCell(k);
						cell.setCellValue(data.get(i)[k]);
					}
				}
			}
			OutputStream os = new FileOutputStream(file);
			wb.write(os);
			os.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * @return clustered data
	 * **/
	public Map<Integer, List<Double[]>> read_clustered(String path,
			String sheetName) {
		if (path == null || path.isEmpty())
			return null;
		Map<Integer, List<Double[]>> map = new HashMap<>();
		Workbook wb = null;
		try {
			File file = new File(path);
			if (!file.exists())
				return null;

			wb = new XSSFWorkbook(new FileInputStream(file));
			Sheet sheet = wb.getSheet(sheetName);
			Row row = sheet.getRow(0);
			int colNum = row.getPhysicalNumberOfCells();
			int rowNum = sheet.getLastRowNum();

			for (int i = 0; i <= rowNum; i++) {
				row = sheet.getRow(i);
				int cluster = (int) row.getCell(colNum - 1)
						.getNumericCellValue();
				List<Double[]> list = null;
				if (map.containsKey(cluster))
					list = map.get(cluster);
				else {
					list = new ArrayList<>();
					map.put(cluster, list);
				}
				Double[] data = new Double[colNum - 1];
				for (int j = 0; j < colNum - 1; j++) {
					Cell cell = row.getCell(j);
					data[j] = cell.getNumericCellValue();
				}
				list.add(data);
				map.put(cluster, list);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}

	public double[][] read(String path, String sheetName) {
		if (path == null || path.isEmpty())
			return null;
		double[][] data = null;
		Workbook wb = null;
		try {
			File file = new File(path);
			if (!file.exists())
				return null;

			wb = new XSSFWorkbook(new FileInputStream(file));
			Sheet sheet = wb.getSheet(sheetName);
			Row row = sheet.getRow(0);
			int colNum = row.getPhysicalNumberOfCells();
			int rowNum = sheet.getLastRowNum();
			data = new double[rowNum + 1][colNum];

			for (int i = 0; i <= rowNum; i++) {
				row = sheet.getRow(i);
				for (int j = 0; j <= colNum - 1; j++) {
					Cell cell = row.getCell(j);
					data[i][j] = cell.getNumericCellValue();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return data;
	}

	public double[][] read(String path, String sheetName, int rows, int cols) {
		if (path == null || path.isEmpty())
			return null;
		double[][] data = null;
		Workbook wb = null;
		try {
			File file = new File(path);
			if (!file.exists())
				return null;

			wb = new XSSFWorkbook(new FileInputStream(file));
			Sheet sheet = wb.getSheet(sheetName);
			Row row = sheet.getRow(0);
			data = new double[rows][cols];

			for (int i = 0; i <rows; i++) {
				row = sheet.getRow(i);
				for (int j = 0; j <= cols - 1; j++) {
					Cell cell = row.getCell(j);
					data[i][j] = cell.getNumericCellValue();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return data;
	}

	public double[] readSingle(String path, String sheetName) {
		if (path == null || path.isEmpty())
			return null;
		double[] data = null;
		Workbook wb = null;
		try {
			File file = new File(path);
			if (!file.exists())
				return null;

			wb = new XSSFWorkbook(new FileInputStream(file));
			Sheet sheet = wb.getSheet(sheetName);
			Row row = sheet.getRow(0);
			int rowNum = sheet.getLastRowNum();
			data = new double[rowNum + 1];

			for (int i = 0; i <= rowNum; i++) {
				row = sheet.getRow(i);
				Cell cell = row.getCell(0);
				data[i] = cell.getNumericCellValue();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return data;
	}

	private void createWorkBook(String fullPathName, String sheetName) {
		try {
			Workbook wb = new XSSFWorkbook();
			OutputStream os = new FileOutputStream(fullPathName);
			if (sheetName != null)
				wb.createSheet(sheetName);
			else
				wb.createSheet();
			wb.write(os);
			os.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public boolean exist(String path) {
		File file = new File(path);
		return file.exists();
	}
}
